#pragma once
#include "BoardLogicBase.h"
#include "BoardFactory.h"
#include "SerializerTmpl.h"
#include "StringSender.h"
#include "Receiver.h"

namespace catan
{
	class BoardLogicServer : public IBoardLogicServer 
	{
	public:
		void AddClient(IBoardLogicClient* client)
		{
			VALID(dynamic_cast<ClientSender*>(client));
			VALID(mClients.size() < 4);

			mClients.push_back(client);
		}

		virtual void OnSEvent(ProtocolBase& protocol){}
		struct ClientSender : public IBoardLogicClient, public IStringSender
		{

			typedef boost::archive::binary_iarchive  InSerializer;

			ClientSender(IStringSender* s)
			{
				mSender = s;
			}
			template <class ProtocolType>
			void OnCEvent(ProtocolType& type)
			{
				std::ostringstream oss;
				boost::archive::binary_oarchive os(oss);
				int header =  type.Type();
				os & header;
				os & type;
				//type.Serialize(os);
				Send(oss.str());
			}

			void Send(const bytestring& str)
			{
				mSender->OnReceive(str);
			}
			virtual void OnReceive(const bytestring& str)
			{
				std::istringstream iss(str);

				InSerializer is(iss);
				mReceiver.OnReceive(is);
			}

			template <class Protocol, class ReceiverType, class Serializer>
			class FunctionBaseTmpl : public Receiver<Serializer>::IFunctionBase<Serializer>
			{
			public:
				FunctionBaseTmpl(ReceiverType* r) : mReceiver(r){}
				virtual void OnReceive(Serializer& ss)
				{
					Protocol p;
					ss >> p;
					mReceiver->OnSEvent(p);
				}
				ReceiverType* mReceiver;
			};

			template <class Protocol>
			ClientSender& Reg()
			{
				mReceiver.Reg<Protocol>(new FunctionBaseTmpl<Protocol, BoardLogicServer, InSerializer>(static_cast<BoardLogicServer*>(mServer)));
				return *this;
			}

			Receiver<InSerializer> mReceiver;

			IStringSender* mSender;
			
		};

		BoardLogicServer(void)
		{
		}

		~BoardLogicServer(void)
		{
		}

		void RegisterEvents()
		{
			FOR_EACH(Clients, it, mClients)
			{
				ClientSender& c = * static_cast<ClientSender*>(*it);
				c
					.Reg<BuildHouseReq>()
					.Reg<BuildRoadReq>()
					.Reg<BuildSettlementReq>()
					.Reg<EndTurnReq>()
					.Reg<DieReq>();
			}
			
		}

		void SendError(){}
		void GameStart()
		{
			BoardFactory f;
			mBoard = f.Create4Board();
			SetGameStart p;
			p.mBoard = mBoard;
			AllEvent(p);

			{
				SetPlayerTrun set;
				set.mColor = mBoard->mPlayers[mBoard->mCurrPlayerNum]->mColor;
				ClientEvent(set, set.mColor);
			}
		}

		virtual void OnSEvent(BuildHouseReq& req)
		{

			if (!CheckStrategyColor(req.mColor) || !CanBuildHouse(req.mColor, req.mId))
			{
				SendError();
				return ;
			}
			BuildHouse(req.mColor, req.mId);

			AllEvent(BuildHouseApply::FromReq(req));
		};

		virtual void OnSEvent(BuildSettlementReq& req)
		{
			if (!CheckStrategyColor(req.mColor) || !CanBuildSettlement(req.mColor, req.mId))
			{
				SendError();
				return ;
			}
			BuildSettlement(req.mColor, req.mId);

			AllEvent(BuildSettlementApply::FromReq(req));
		}

		virtual void OnSEvent(BuildRoadReq& req)
		{
			if (!CheckStrategyColor(req.mColor) || !CanBuildRoad(req.mColor, req.mId))
			{
				SendError();
				return ;
			}
			BuildRoad(req.mColor, req.mId);

			AllEvent(BuildRoadApply::FromReq(req));
		}

		virtual void OnSEvent(BuyCardReq& req)
		{
			if (!CheckStrategyColor(req.mColor) || !CanBuyDevelopmentCard(req.mColor))
			{
				SendError();
				return ;
			}
			Handle<DevelopmentCard> card = BuyDevelopCard(req.mColor);
			if (!card)
			{
				LogError(_T("sth wrong"));
				return;
			}
			BuyCardApply apply;
			apply.mColor = req.mColor;
			apply.mDevelopmentCard = card;
			AllEvent(apply, req.mColor);
			ClientEvent(apply, req.mColor);
		}

		virtual void OnSEvent(EndTurnReq& req)
		{
			if (!CheckStrategyColor(req.mColor))
			{
				return;
			}
			EndTurnApply apply;
			apply.mResult = Result::Succeed;
			apply.mColor = req.mColor;
			AllEvent(apply);
			NextColor();
			SetPlayerTrun set;
			set.mColor = mBoard->mPlayers[mBoard->mCurrPlayerNum]->mColor;
			ClientEvent(set, set.mColor);
		}

		virtual void OnSEvent(DieReq& req)
		{
			if (!CheckStrategyColor(req.mColor))
			{
				return;
			}
			DieApply apply;
			
			apply.mDieNumber = DieNum();

			AllEvent(apply);
			if (apply.mDieNumber.GetTotal() == Robber::DieNum())
			{
			}
			else
			{
				Fields fields;
				FindDieFiled(apply.mDieNumber.GetTotal(), fields);
				PlayersHarvestResourceCards playersCards;
				GetPlayerHarvestResourceCards(fields, playersCards);
				PlayersHarvestApply apply;
				apply.playersHarvestResourceCards = &playersCards;
				AllEvent(apply);
			}

			//mBoard->mFields
		}

		virtual void OnSEvent(UseCardReq& req)
		{
			// 			CanUsereq.mDevelopmentCard
			// 			req.
		}




		// 			mClients->createboard(board)
		// 			randomplayertime;
		// 			mClients->send 1;
		// 			wait();
		// 			mClients->send 2;
		// 			wait();
		// 
		// 			mClients->send 3;
		// 			wait;
		// 
		// 			mClients->send 4;
		// 			wait;
		// 			
		// 			wait die();
		// 			die()
		// 
		// 		}

		// 		IBoardLogicClient* IBoardLogicServer::GetBoardLogicClient( PlayerColor::Enum color )
		// 		{
		// 			for (Clients::iterator it = mClients.begin(); 
		// 				it != mClients.end(); ++it)
		// 			{
		// 				IBoardLogicClient* c = *it;
		// 				if (c->GetColor() == color)
		// 				{
		// 					return c;
		// 				}
		// 			}
		// 			LogError("No playerClient");
		// 			return NULL;
		// 		}

		ClientSender* GetBoardLogicClient( PlayerColor::Enum color )
		{
			for (Clients::iterator it = mClients.begin(); 
				it != mClients.end(); ++it)
			{
				IBoardLogicClient* c = *it;
				if (c->GetColor() == color)
				{
					return static_cast<ClientSender*>(c);
				}
			}
			LogError(_T("No playerClient"));
			return NULL;
		}
	protected:
		template <class Protocol> void AllEvent(Protocol& protocol, PlayerColor::Enum exceptColor = PlayerColor::Num)
		{
			for (Clients::iterator it = mClients.begin(); 
				it != mClients.end(); ++it)
			{
				IBoardLogicClient* c = *it;
				if (c->GetColor() != exceptColor)
				{
					static_cast<ClientSender*>(c)->OnCEvent(protocol);
				}
			}
		}

		template <class Protocol> void ClientEvent(Protocol& protocol, PlayerColor::Enum color)
		{
			for (Clients::iterator it = mClients.begin(); 
				it != mClients.end(); ++it)
			{
				IBoardLogicClient* c = *it;
				if (c->GetColor() == color)
				{
					static_cast<ClientSender*>(c)->OnCEvent(protocol);
				}
			}
		}

		typedef std::vector<IBoardLogicClient*> Clients;
		Clients mClients;
	};

}	